package sf.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;

import java.util.Map;

@Slf4j
public class JsonUtil {
    private static ObjectMapper objectMapper = new ObjectMapper();

    private final static String dateFormatPattern = "yyyy-MM-dd HH:mm:ss";

    static {
        // 排除值为空属性
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 转换成对象时，没有属性的处理，忽略掉
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

        // 进行缩进输出
        // configure(SerializationFeature.INDENT_OUTPUT, true);
        // 进行日期格式化
//        if (dateFormatPattern !=null) {
//            DateFormat dateFormat = new SimpleDateFormat(dateFormatPattern);
//            objectMapper.setDateFormat(dateFormat);
//        }
        objectMapper.registerModule(new JavaTimeModule());

    }

    public static ObjectMapper getObjectMapper() {
        return objectMapper;
    }

    /**
     * 将 POJO 对象转为 JSON 字符串
     */
    public static <T> String toJson(T pojo) {
        String json;
        try {
            json = objectMapper.writeValueAsString(pojo);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("转换json格式异常");
        }
        return json;
    }

    /**
     * 将 JSON 字符串转为 POJO 对象,json为空串，内部会转换错误
     * @param json
     * @param type
     * @param <T>
     * @return
     */
    public static <T> T fromJson(String json, Class<T> type) {
        T pojo = null;
        if (ObjectUtils.isNotEmpty(json)) {
            try {
                pojo = objectMapper.readValue(json, type);
            } catch (Exception e) {
                log.error("json格式错误串:{}，Class:{}", json, type, e);
                throw new RuntimeException("json格式错误");
            }
        } else {
            log.warn("json格式错误串为空，Class：{}", type);
        }
        return pojo;
    }

    /**
     * JSON串转换为Java泛型对象，可以是各种类型，此方法最为强大。用法看测试用例。
     * @param <T>
     * @param jsonStr           JSON字符串
     * @param typeReference,例如: new TypeReference< List<FamousUser> >(){}
     * @return List对象列表
     */
    public static <T> T toCollection(String jsonStr, TypeReference<T> typeReference) {
        try {
            return objectMapper.readValue(jsonStr, typeReference);
        } catch (Exception e) {
            throw new RuntimeException("json格式错误" + jsonStr);
        }
    }

    /**
     * JSON串转换为Java泛型对象，可以是各种类型，且泛型可嵌套     *
     * @param <T>               泛型
     * @param jsonStr           JSON字符串
     * @param typeReference,例如: new TypeReference< List<FamousUser> >(){}
     * @return 反序列化后的对象
     */
    public static <T> T toPojo(String jsonStr, TypeReference<T> typeReference) {
        try {
            return objectMapper.readValue(jsonStr, typeReference);
        } catch (Exception e) {
            throw new RuntimeException("json格式错误" + jsonStr);
        }
    }

    /**
     * JSON串转换为Java泛型对象，可以是各种类型，且泛型可嵌套     *
     * @param <T>     泛型
     * @param jsonStr JSON字符串
     * @param
     * @return 反序列化后的对象
     */
    public static <T> T toPojo(String jsonStr, Class outer, Class inner) {
        try {
            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(outer, inner);
            return objectMapper.readValue(jsonStr, javaType);
        } catch (Exception e) {
            throw new RuntimeException("json格式错误" + jsonStr);
        }
    }

    @SuppressWarnings("unchecked")
    public static Map<String, Object> json2map(String jsonStr) {
        try {
            return objectMapper.readValue(jsonStr, Map.class);
        } catch (Exception e) {
            throw new RuntimeException("json格式错误" + jsonStr);
        }
    }
}
